package cn.donting.jme.utile;

import cn.hutool.core.collection.EnumerationIter;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ResourcesUtil {

    private String packageDirName;
    private Set<String> resources = new HashSet<>();

    public Set<String> scanResources(String... pack) throws IOException {
        for (String pname : pack) {
            this.packageDirName = pname.replace(CharUtil.DOT, File.separatorChar);
            Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(pname);
            while (resources.hasMoreElements()) {
                URL url = resources.nextElement();
                switch (url.getProtocol()) {
                    case "file":
                        scanFile(new File(URLUtil.decode(url.getFile(), StandardCharsets.UTF_8)), null);
                        break;
                    case "jar":
                        scanJar(URLUtil.getJarFile(url));
                        break;
                }
            }
        }

        return this.resources;
    }


    private void scanFile(File file, String rootDir) throws MalformedURLException {
        final String fileName = file.getAbsolutePath();
        if (file.isFile()) {
            final String className = fileName//
                    // 8为classes长度，fileName.length() - 6为".class"的长度
                    .substring(rootDir.length(), fileName.length());
            resources.add(className);
        } else if (fileName.endsWith(FileUtil.JAR_FILE_EXT)) {
            try {
                scanJar(new JarFile(file));
            } catch (IOException e) {
                throw new IORuntimeException(e);
            }
        } else if (file.isDirectory()) {
            final File[] files = file.listFiles();
            if (null != files) {
                for (File subFile : files) {
                    scanFile(subFile, (null == rootDir) ? subPathBeforePackage(file) : rootDir);
                }
            }
        }
    }

    /**
     * 扫描jar包，扫描结束后关闭jar文件
     *
     * @param jar jar包
     */
    private void scanJar(JarFile jar) {
        try {
            String name;
            for (JarEntry entry : new EnumerationIter<>(jar.entries())) {
                name = StrUtil.removePrefix(entry.getName(), StrUtil.SLASH);
                if (!entry.isDirectory()) {
                    resources.add(name);
                }
            }
        } finally {
            IoUtil.close(jar);
        }
    }

    /**
     * 截取文件绝对路径中包名之前的部分
     *
     * @param file 文件
     * @return 包名之前的部分
     */
    private String subPathBeforePackage(File file) {
        String filePath = file.getAbsolutePath();
        if (StrUtil.isNotEmpty(this.packageDirName)) {
            filePath = StrUtil.subBefore(filePath, this.packageDirName, true);
        }
        return StrUtil.addSuffixIfNot(filePath, File.separator);
    }
}
